from eden.evo.cell import NonsexualCell
import doctest

def cmp_fitness(cell1, cell2):
    return -cmp(cell1.fitness, cell2.fitness)

class Reproducer:
    def __init__(self, mutators):
        self.mutators = mutators
        
    def select_top_half(self, cells):
        '''
        >>> from eden.evo.cell import *
        >>> cells = []
        >>> for i in range(10):
        ...     cell = NonsexualCell(None, None)
        ...     cell.fitness = i
        ...     cells.append(cell)
        >>> NonsexualReproducer(None).select_top_half(cells)
        >>> len(cells)
        5
        >>> [cell.fitness for cell in cells]
        [9, 8, 7, 6, 5]
        '''
        cells.sort(cmp_fitness)
        del cells[len(cells) / 2 : len(cells)]
    
    def reset_cells(self, cells):
        '''
        >>> cells = []
        >>> for i in range(5):
        ...     cell = NonsexualCell(None, None)
        ...     cell.fitness = i
        ...     cells.append(cell)
        >>> NonsexualReproducer(None).reset_cells(cells)
        >>> [cell.fitness for cell in cells]
        [0.0, 0.0, 0.0, 0.0, 0.0]
        '''
        for cell in cells:
            cell.reset()
    
    def reproduce(self, cells, generation):
        '''
        >>> cells = []
        >>> for i in range(10):
        ...     cell = NonsexualCell(None, None)
        ...     cell.fitness = i
        ...     cells.append(cell)
        >>> NonsexualReproducer(()).reproduce(cells, 1)
        >>> len(cells)
        10
        '''
        self.select_top_half(cells)
        self.reset_cells(cells)
        self.clone_cells(cells, generation)
    
    def clone_chromosome(self, chromosome):
        '''
        >>> from eden.evo.chromosome import *
        >>> src = Chromosome(())
        >>> dest = NonsexualReproducer(()).clone_chromosome(src)
        >>> isinstance(dest, Chromosome)
        True
        '''
        cloned = chromosome
        for mutator in self.mutators:
            cloned = mutator.mutate(cloned)
        return cloned
    
class NonsexualReproducer(Reproducer):
    def clone_cells(self, cells, generation):
        '''
        >>> cells = [NonsexualCell(None, None) for i in range(5)]
        >>> NonsexualReproducer(()).clone_cells(cells, 1)
        >>> len(cells)
        10
        >>> [cell.generation for cell in cells]
        [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
        '''
        newcells = [self.clone_cell(cell) for cell in cells]
        for cell in newcells:
            cell.generation = generation
        cells.extend(newcells)
        
    def clone_cell(self, cell):
        '''
        >>> from eden.evo.chromosome import *
        >>> from eden.evo.codon import *
        >>> chromosome = Chromosome((Codon(1, 1, 1), ))
        >>> src = NonsexualCell(chromosome, None)
        >>> dest = NonsexualReproducer(()).clone_cell(src)
        >>> isinstance(dest, NonsexualCell)
        True
        >>> isinstance(dest.getchromosome(), Chromosome)
        True
        >>> dest.gettranslator() == src.gettranslator()
        True
        '''
        chromosome = self.clone_chromosome(cell.getchromosome())
        return NonsexualCell(chromosome, cell.gettranslator())
    
class SexualReproducer(Reproducer):
    pass
        
if __name__ == '__main__':
    doctest.testmod()